#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "relayer.h"

#define BUFSIZE 1024

//状态机的状态
enum
{
    STATE_R = 1,
    STATE_W,
    STATE_Ex,
    STATE_T,
};
//状态机结构体变量类型
struct rel_fsm_st
{
    int state;          //状态机状态
    int sfd;            //源文件描述符
    int dfd;            //目的文件描述符
    char buf[BUFSIZE];  //缓冲区
    int len;            //缓冲区内数据大小
    int pos;            //缓冲区的光标
    char * errstr;      //
    int64_t count;      //
};
//任务结构体类型
struct rel_job_st
{
    int job_state;      //任务状态
    int fd1;            //文件描述符
    int fd2;            //文件描述符
    int fd1_save;       //原始
    int fd2_save;       //原始
    struct rel_fsm_st fsm12;    //状态机
    struct rel_fsm_st fsm21;    //状态机
};

static struct rel_job_st * rel_job[REL_JOBMAX];                 //任务数组
static pthread_mutex_t mut_rel_job = PTHREAD_MUTEX_INITIALIZER; //一把互斥锁
static pthread_once_t init_once = PTHREAD_ONCE_INIT;            //一个条件变量

//驱动
static void fsm_driver(struct rel_fsm_st * fsm)
{
    int ret;
    //重看状态机结构体的状态成员值
    switch (fsm->state)
    {
    case STATE_R:
        //读数据从源文件到缓冲区
        fsm->len = read(fsm->sfd, fsm->buf, BUFSIZE);
        if(fsm->len == 0)           //缓冲区内无数据
            fsm->state = STATE_T;   //状态改为T
        else if(fsm->len < 0)       //异常值
        {
            if(errno == EAGAIN)
                fsm->state = STATE_R;
            else
            {
                fsm->errstr = "read";   //报错
                fsm->state = STATE_Ex;  //状态改为Ex
            }
        }
        else
        {
            fsm->pos = 0;
            fsm->state = STATE_W;
        }
        break;

    case STATE_W:
        //写数据从缓冲区到目的文件
        ret = write(fsm->dfd, fsm->buf + fsm->pos, fsm->len);
        if(ret < 0)                     //异常值
        {
            if(errno == EAGAIN)
                fsm->state = STATE_W;
            else
            {
                fsm->errstr = "write";  //报错
                fsm->state = STATE_Ex;  //状态改为Ex
            }
        }
        else
        {
            fsm->pos += ret;            //移动光标
            fsm->len -= ret;            //减少缓冲区数据量
            if(fsm->len == 0)           //若缓冲区内数据已经写完
                fsm->state = STATE_R;   //状态机状态设置为读
            else
                fsm->state = STATE_W;
        }
        break;

    case STATE_Ex:
        perror(fsm->errstr);            //报错
        fsm->state = STATE_T;           //状态机状态设置为T
        break;

    case STATE_T:
        /*do smthing*/
        break;

    default:
        abort();
        break;
    }
}

//线程
static void * thr_relayer(void * p)
{
    int i;
    while(1)
    {
        usleep(1000*200);
        pthread_mutex_lock(&mut_rel_job);
        for(i = 0; i < REL_JOBMAX; i++) //每隔200ms执行所有符合条件的驱动
        {
            if(rel_job[i] != NULL)
            {
                if(rel_job[i]->job_state == STATE_RUNNING)
                {
                    fsm_driver(&rel_job[i]->fsm12);
                    fsm_driver(&rel_job[i]->fsm21);
                    if(rel_job[i]->fsm12.state == STATE_T && rel_job[i]->fsm21.state == STATE_T)
                        rel_job[i]->job_state = STATE_OVER;
                }
            }
        }
        pthread_mutex_unlock(&mut_rel_job);
    }
}

//加载模块
void module_load(void)
{
    pthread_t tid_relayer;
    int err;
    //创建一个线程
    err = pthread_create(&tid_relayer, NULL, thr_relayer, NULL);
    if(err)
    {
        fprintf(stderr, "load creat%s\n", strerror(err));
        exit(1);
    }
}
//卸载模块
void module_unload(void){return;}

static int get_free_pos_unlock()
{
    int i;
    for(i = 0; i < REL_JOBMAX; i++)
    {
        if(rel_job[i] == NULL)
            return i;
    }
    return -1;
}

int rel_addjob(int fd1, int fd2)
{
    int pos;
    struct rel_job_st *me;
    //加载模块函数,只执行一次
    pthread_once(&init_once, module_load);
    //为任务结构体变量申请空间
    me = malloc(sizeof(*me));
    if(me == NULL)
        return -ENOMEM;
    //设置任务结构体成员
    //两个文件描述符
    me->fd1 = fd1;
    me->fd2 = fd2;
    //任务的状态
    me->job_state = STATE_RUNNING;
    //保存文件初始的状态,并设置为非阻塞
    me->fd1_save = fcntl(me->fd1, F_GETFL);
    fcntl(me->fd1, F_SETFL, me->fd1_save|O_NONBLOCK);
    me->fd2_save = fcntl(me->fd2, F_GETFL);
    fcntl(me->fd2, F_SETFL, me->fd2_save|O_NONBLOCK);
    //设置状态机1
    me->fsm12.sfd = me->fd1;
    me->fsm12.dfd = me->fd2;
    me->fsm12.state = STATE_R;
    //设置状态机2
    me->fsm21.sfd = me->fd2;
    me->fsm21.dfd = me->fd1;
    me->fsm21.state = STATE_R;

    pthread_mutex_lock(&mut_rel_job);           //上锁
    pos = get_free_pos_unlock();                //获取空位置
    if(pos <0)
    {
        pthread_mutex_unlock(&mut_rel_job);
        fcntl(me->fd1, F_SETFL, me->fd1_save);
        fcntl(me->fd2, F_SETFL, me->fd2_save);
        free(me);
        return -ENOSPC;
    }
    rel_job[pos] = me;                          //自述下标
    pthread_mutex_unlock(&mut_rel_job);         //解锁

    return pos;
}
/*
 * >=0 当前任务ID
 * -EINVAL 参数非法
 * -ENOSPC 任务数满
 * -ENOMEM 内存申请失败
 * */
int rel_cancel(int id)
{}
/*
 * == 0 成功
 * -EINVAL 参数非法
 * -EBUSY  已被取消
 * */
int rel_waitjob(int id, struct rel_stat_st *ptr)
{}
/*
 * == 0 成功 已经终止并返回状态
 * -EINVAL 参数非法
 * */
int rel_statjob(int id, struct rel_stat_st *ptr)
{}
/*
 * == 0 成功 指定任务状态已经返回
 * -EINVAL 参数非法
 * */